package com.test.lock.CLHAndMCS;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * MCS自旋锁
 *
 * @author wangjie
 * @version V1.0
 * @date 2019/12/20
 */
public class MCSLock {

    /**
     * 链表节点
     */
    public static class MCSNode {
        volatile MCSNode next;
        volatile boolean isWaiting = true; // 默认是在等待锁
        MCSNode(){

        }
    }

    /**
     * 指向最后一个申请锁的MCSNode
     */
    volatile MCSNode queue;


    /**
     * 一个基于反射的工具类，它能对指定类的指定的volatile引用字段进行原子更新。(注意这个字段不能是private的)
     *
     * 通过调用AtomicReferenceFieldUpdater的静态方法newUpdater就能创建它的实例，该方法要接收三个参数：
     *     包含该字段的对象的类
     *     将被更新的对象的类
     *     将被更新的字段的名称
     */
    private static final AtomicReferenceFieldUpdater<MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater
            .newUpdater(MCSLock.class, MCSNode.class, "queue");


    public void lock(MCSNode currentThread) {

        System.out.println(Thread.currentThread().getName()+"\t come in");

        /**
         * 原子更新该更新器管理的指定对象的字段的值为newValue，返回旧值
         */
        MCSNode predecessor = UPDATER.getAndSet(this, currentThread);
        //前个节点不为null
        if (predecessor != null) {
            //设置前一个节点指向当前节点
            predecessor.next = currentThread;
            while (currentThread.isWaiting) {
                //自旋自己的isWaiting
                System.out.println(Thread.currentThread().getName()+"\t Waiting");
            }
        } else { // 只有一个线程在使用锁，没有前驱来通知它，所以得自己标记自己已获得锁
            currentThread.isWaiting = false;
            System.out.println(Thread.currentThread().getName()+"\t get lock");
        }
    }

    public void unlock(MCSNode currentThread) {

        System.out.println(Thread.currentThread().getName()+"\t in UnLock()");

        if (currentThread.isWaiting) {
            return;
        }
         // 检查是否有人排在自己后面
        if (currentThread.next == null) {
            if (UPDATER.compareAndSet(this, currentThread, null)) {
                // compareAndSet返回true表示确实没有人排在自己后面
                return;
            } else {
                // 突然有人排在自己后面了，可能还不知道是谁，下面是等待后续者
                while (currentThread.next == null) {
                }
            }
        }
        currentThread.next.isWaiting = false;
        // 辅助GC
        currentThread.next = null;
    }

    public static void main(String[] args) {

        MCSLock mCSLock = new MCSLock();

        new Thread(()->{
            MCSNode node = new MCSNode();
            mCSLock.lock(node);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mCSLock.unlock(node);
        },"AA").start();

        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            MCSNode node = new MCSNode();
            mCSLock.lock(node);
            mCSLock.unlock(node);
        },"BB").start();

    }
}
